"""
使用Python生成阿里云需要的签名：
https://blog.csdn.net/m0_37549390/article/details/106806480

阿里云的签名机制：
https://help.aliyun.com/document_detail/30563.html?spm=a2c4g.11186623.6.754.750d47cdLYdFMA

阿里云API的公共参数：
https://help.aliyun.com/document_detail/30561.html?spm=a2c4g.11186623.2.13.7c02295cUKe4b9

获取物联网设备上传数据的阿里云接口：
https://help.aliyun.com/document_detail/69539.html?spm=a2c4g.11186623.2.97.25b33112Y5d7kF#reference-q2q-krz-wdb

ProductKey: a15NNbDLsRb
DeviceName: ESP32_MicroPython
DeviceSecret: b48e507d6148b9c821f0716c37c2d328
AccessKeySecret: j1EiOpZuBmzH7fC9dS1wz31kzlTCoI
"""
import random
import hmac
import base64
import json
from urllib.request import Request, urlopen
from http.client import HTTPResponse
from hashlib import sha1
from urllib import parse
from datetime import datetime, timedelta


def __generate_ali_signature(params: dict, access_key_secret: str) -> str:
    # 排序并进行转义
    sig = parse.urlencode(sorted(list(params.items()), key=lambda x: x[0]))
    print(sig)
    sig = parse.quote_plus(sig)
    print(sig)
    # 组成加密用消息
    sig = 'GET&' + parse.quote_plus('/') + '&' + sig
    print(sig)
    # 加密
    h = hmac.new((access_key_secret + '&').encode(), sig.encode(), sha1)
    sig = base64.encodebytes(h.digest()).strip().decode()
    print(sig)
    return sig


def __generate_common_parameter_and_host() -> (dict, str):
    now_utc = datetime.now() - timedelta(hours=8)  # need utc time as parameter
    params = {
        'Format': 'JSON',
        'Version': '2018-01-20',
        'AccessKeyId': 'LTAI4GDJZYHdgyDNgDnVp2nC',
        'SignatureMethod': 'HMAC-SHA1',
        'Timestamp': f'{now_utc.year}-{now_utc.month:02}-{now_utc.day:02}T' +
                     f'{now_utc.hour:02}:{now_utc.minute:02}:{now_utc.second:02}Z',
        'SignatureVersion': '1.0',
        'SignatureNonce': str(random.randint(0, 1_0000_0000)),  # 每一次请求都要不同
        'RegionId': 'cn-shanghai',
    }
    return params, 'https://iot.cn-shanghai.aliyuncs.com/'


def query_device_property_data(prop: str, since: datetime) -> list:
    since = int(since.timestamp() * 1000)
    res = []

    while True:
        common_params, host = __generate_common_parameter_and_host()

        special_params = {
            'Action': 'QueryDevicePropertyData',
            'Asc': 0,
            'StartTime': since,
            'EndTime': int(datetime.now().timestamp() * 1000),
            'Identifier': prop,
            'PageSize': 50,
            'DeviceName': 'ESP32_MicroPython',
            'ProductKey': 'a15NNbDLsRb',
        }

        signature = __generate_ali_signature(
            params=dict(**common_params, **special_params),
            access_key_secret='j1EiOpZuBmzH7fC9dS1wz31kzlTCoI',
        )

        all_params = dict(**common_params, **special_params, Signature=signature)
        request_url = host + '?' + parse.urlencode(all_params)
        prop_data = json.load(urlopen(request_url))
        res += prop_data['Data']['List']['PropertyInfo']

        if prop_data['Data']['NextValid']:
            since = prop_data['Data']['NextTime']
        else:
            break
    return res


def query_device_property_status() -> list:
    common_params, host = __generate_common_parameter_and_host()
    special_params = {
        'Action': 'QueryDevicePropertyStatus',
        'DeviceName': 'ESP32_MicroPython',
        'ProductKey': 'a15NNbDLsRb',
    }
    signature = __generate_ali_signature(
        params=dict(**common_params, **special_params),
        access_key_secret='j1EiOpZuBmzH7fC9dS1wz31kzlTCoI',
    )
    all_params = dict(**common_params, **special_params, Signature=signature)
    request_url = host + '?' + parse.urlencode(all_params)
    return json.load(urlopen(request_url))['Data']['List']['PropertyStatusInfo']


if __name__ == '__main__':
    data = query_device_property_status()
    for i in data:
        print(i)
    
    print('-' * 100)
    
    print('\nhumidity: ')
    data = query_device_property_data('humidity', datetime.now() - timedelta(days=1))
    for i in data:
        val = int(i['Value'])
        time = datetime.fromtimestamp(int(i['Time']) / 1000)
        print(
            f'{val}%, {time.year:04}-{time.month:02}-{time.day:02} ' +
            f'{time.hour:02}:{time.minute:02}:{time.second:02}'
        )
    
    print('\ntemperature1:')
    data = query_device_property_data('temperature1', datetime.now() - timedelta(days=1))
    for i in data:
        val = float(i['Value'])
        time = datetime.fromtimestamp(int(i['Time']) / 1000)
        print(
            f'{val:.03f}℃, {time.year:04}-{time.month:02}-{time.day:02} ' +
            f'{time.hour:02}:{time.minute:02}:{time.second:02}'
        )
    
    print('\ntemperature2:')
    data = query_device_property_data('temperature2', datetime.now() - timedelta(days=1))
    for i in data:
        val = int(i['Value'])
        time = datetime.fromtimestamp(int(i['Time']) / 1000)
        print(
            f'{val}℃, {time.year:04}-{time.month:02}-{time.day:02} ' +
            f'{time.hour:02}:{time.minute:02}:{time.second:02}'
        )
